home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Printing / PDlog Expand / PDlog Expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-29  |  12.1 KB  |  393 lines  |  [TEXT/KAHL]

  1. /* PDlog Expand.c    Derived from TN #95.
  2.  
  3. Dave Hersey, Apple Developer Technical Support.
  4.  
  5.   10/9/91…    v1.0
  6.   2/25/92…  v1.0.1 --> fixed lack of print handle tossing and added something to print.       <dmh>
  7.   9/29/93…  v1.0.2 --> fixed bug in Append_DITL (also in TN #95) which appends 2 extra bytes. <dmh>
  8.  
  9. Think C 5.0.3 source.
  10.  
  11.    NOTE: Apple reserves the top half of the screen (where the current DITL
  12.    items are located). Applications may use the bottom half of the screen to
  13.    add items, but should not change any items in the top half of the screen.
  14.    An application should expand the print dialogs only as much as is
  15.    absolutely necessary.
  16.  
  17.    A global search and replace of 'Job' with 'Stl' will produce code that
  18.    modifies the style dialog.
  19.  
  20. */
  21.  
  22. #include <PrintTraps.h>
  23.  
  24. static TPPrDlg PrtJobDialog;        /* pointer to job dialog */
  25.  
  26. /* This points to the following structure:
  27.     
  28. struct { 
  29.         DialogRecord  Dlg;        (The Dialog window)
  30.         ProcPtr       pFltrProc;  (The Filter Proc.)
  31.         ProcPtr       pItemProc;  (The Item evaluating proc - we'll change this)
  32.         THPrint       hPrintUsr;  (The user's print record.)
  33.         Boolean       fDoIt;    
  34.         Boolean       fDone;    
  35.             (Four longs -- reserved by Apple Computer)
  36.         long          lUser1;         
  37.         long          lUser2;        
  38.         long          lUser3;    
  39.         long          lUser4;        
  40. } TPrDlg; *TPPrDlg;          
  41. */
  42.  
  43. /* Declare ‘pascal’ functions and procedures */
  44.  
  45. extern int        Append_DITL(TPPrDlg, int);            /* Our AppendDITL function.            */
  46. extern pascal    TPPrDlg MyJobDlgInit(THPrint);        /* Our extention to PrJobInit.        */
  47. extern pascal    void MyJobItems(TPPrDlg, short);    /* Our modal item handler.            */
  48. extern OSErr    Print(void);
  49.  
  50. #define MyDITL 256  /* resource ID of my DITL to be spliced onto job dialog */
  51.  
  52. THPrint hPrintRec;          /* handle to print record */
  53. long prFirstItem;           /* save our first item here */
  54. long prPItemProc;           /* we need to store the old itemProc here */
  55.  
  56. /*-----------------------------------------------------------------------*/
  57.     WindowPtr   MyWindow;
  58.     OSErr       err;
  59.     Str255      myStr;
  60.  
  61. typedef
  62.     struct dialog_item_struct
  63.     {
  64.         Handle  handle;     /* handle or procedure pointer for this item */
  65.         Rect    bounds;     /* display rectangle for this item */
  66.         char    type;       /* item type - 1 */
  67.         char    data[1];    /* length byte of data */
  68.     }
  69.     DialogItem, *DialogItemPtr, **DialogItemHandle;
  70.  
  71. typedef
  72.     struct append_item_list_struct
  73.     {
  74.         int           max_index; /* number of items - 1 */
  75.         DialogItem    items[1]; /* first item in the array */
  76.     }
  77.     ItemList, *ItemListPtr, **ItemListHandle;
  78.  
  79. typedef
  80.     union signed_byte_union
  81.     {
  82.         int        integer;
  83.         char    bytes[2];
  84.     }
  85.     ByteAccess;
  86.  
  87.  
  88. /*    This routine appends all of the items of a specified DITL    */
  89. /*    onto the end of a specified DLOG — We don’t even need to know the format    */
  90. /*    of the DLOG    */
  91.  
  92. /*    this will be done in 3 steps:    */
  93. /*     1. append the items of the specified DITL onto the existing DLOG    */
  94. /*     2. expand the original dialog window as required    */
  95. /*     3. return the adjusted number of the first new user item    */
  96.  
  97.  
  98. int Append_DITL(TPPrDlg dialog, int item_list_ID)
  99. {
  100.     Point             offset;
  101.     Rect            max_rect;
  102.     ItemListHandle     append_item_list;    /* handle to DITL being appended */
  103.     DialogItemPtr     item;                /* pointer to item being appended */
  104.     ItemListHandle    dlg_item_list;        /* handle to DLOG's item list */
  105.     int               first_item;
  106.     int                new_items, data_size, i;
  107.     ByteAccess        usb;
  108.     OSErr              err;
  109.  
  110. /*
  111.     Using the original DLOG
  112.  
  113.     1. Remember the original window Size.
  114.     2. Set the offset Point to be the bottom of the original window.
  115.     3. Subtract 5 pixels from bottom and right, to be added
  116.        back later after we have possibly expanded window.
  117.     4. Get working Handle to original item list.
  118.     5. Calculate our first item number to be returned to caller.
  119.     6. Get locked Handle to DITL to be appended.
  120.     7. Calculate count of new items.
  121. */
  122.  
  123.     if (dialog == NULL) ExitToShell();
  124.  
  125.     max_rect = ((DialogPeek)dialog)->window.port.portRect;
  126.     offset.v = max_rect.bottom;
  127.     offset.h = 0;
  128.     max_rect.bottom -= 5;
  129.     max_rect.right -= 5;
  130.  
  131.     dlg_item_list = (ItemListHandle)((DialogPeek)dialog)->items;
  132.     first_item = (**dlg_item_list).max_index + 2;
  133.  
  134.     append_item_list = (ItemListHandle)GetResource('DITL', item_list_ID);
  135.     if ( append_item_list == NULL )
  136.         return first_item;
  137.  
  138.     HLock((Handle)append_item_list);
  139.     new_items = (**append_item_list).max_index + 1;
  140.  
  141. /*
  142.      For each item,
  143.       1. Offset the rectangle to follow the original window.
  144.       2. Make the original window larger if necessary.
  145.       3. fill in item handle according to type.
  146. */
  147.  
  148.     item = (**append_item_list).items;
  149.     for ( i = 0; i < new_items; i++ )
  150.     {
  151.         OffsetRect(&item->bounds, offset.h, offset.v);
  152.         UnionRect(&item->bounds, &max_rect, &max_rect);
  153.         usb.integer = 0;
  154.         usb.bytes[1] = item->data[0];
  155.  
  156.         switch ( item->type & 0x7F )
  157.         {
  158.             case ctrlItem + btnCtrl :
  159.             case ctrlItem + chkCtrl :
  160.             case ctrlItem + radCtrl :
  161.                 item->handle = (Handle)NewControl((DialogPtr) dialog,
  162.                                                   &item->bounds,
  163.                                                   (StringPtr)item->data,
  164.                                                   TRUE,
  165.                                                   0, 0, 1,
  166.                                                   item->type & 0x03,
  167.                                                   0);
  168.             break;
  169.  
  170.             case ctrlItem + resCtrl :
  171.             {
  172.                 item->handle = (Handle)GetNewControl(*(int*)(item->data + 1), (DialogPtr) dialog);
  173.                 (**(ControlHandle)item->handle).contrlRect = item->bounds;
  174.             }
  175.             break;
  176.  
  177.             case statText :
  178.             case editText :
  179.                 err = PtrToHand(item->data + 1, &item->handle, usb.integer);
  180.             break;
  181.  
  182.             case iconItem :
  183.                 item->handle = GetIcon(*(int*)(item->data + 1));
  184.             break;
  185.  
  186.             case picItem :
  187.                 item->handle = (Handle)GetPicture(*(int*)(item->data + 1));
  188.             break;
  189.  
  190.             default :
  191.                 item->handle = NULL;
  192.         }
  193.  
  194.         data_size = (usb.integer + 1) & 0xFFFE;
  195.         item = (DialogItemPtr)((char*)item + data_size + sizeof(DialogItem));
  196.     }
  197.  
  198.  // We need to subtract the short below because otherwise the size of the DITL count
  199.  // gets factored in twice, and the resulting DTIL has two bytes of garbage appended
  200.  // to it.  This is a problem with the original TN#95 code as well.
  201.  
  202.     err = PtrAndHand((**append_item_list).items,
  203.                      (Handle)dlg_item_list,
  204.                      GetHandleSize((Handle) append_item_list)
  205.                      - sizeof(short));
  206.  
  207.     (**dlg_item_list).max_index += new_items;
  208.     HUnlock((Handle) append_item_list);
  209.     ReleaseResource((Handle) append_item_list);
  210.  
  211.     max_rect.bottom += 5;
  212.     max_rect.right += 5;
  213.     SizeWindow((WindowPtr) dialog, max_rect.right, max_rect.bottom, TRUE);
  214.  
  215.     return first_item;
  216. }
  217.  
  218.  
  219. /*------------------------------------------------------------------------*/
  220.  
  221. OSErr Print()
  222. {
  223.     TPPrPort    pPrPort;
  224.     Rect        aRect;
  225.     TPrStatus    theStatus;
  226.     
  227.     
  228.     /* call PrJobInit to get pointer to the invisible job dialog */
  229.     hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));
  230.     PrintDefault(hPrintRec);
  231.     PrValidate(hPrintRec);
  232.     if (PrError() != noErr)
  233.         return PrError();        
  234.  
  235.     PrtJobDialog = PrJobInit(hPrintRec);
  236.        
  237.     if (PrError() != noErr)
  238.         return PrError();        
  239.  
  240.     if (!PrDlgMain(hPrintRec, (ProcPtr) &MyJobDlgInit)) /* this line does all the stuff */
  241.         return iPrAbort;
  242.  
  243.     if (PrError() != noErr)
  244.         return PrError();        
  245.  
  246.     pPrPort = PrOpenDoc(hPrintRec, NULL, NULL);
  247.     PrOpenPage(pPrPort, NULL);
  248.     
  249.     aRect = (*hPrintRec)->prInfo.rPage;
  250.     InsetRect(&aRect, 20, 20);
  251.     PenSize(4, 4);
  252.     FrameRect(&aRect);
  253.     
  254.     PrClosePage(pPrPort);
  255.     PrCloseDoc(pPrPort);
  256.  
  257.     if (!PrError() && (*hPrintRec)->prJob.bJDocLoop == bSpoolLoop)
  258.         PrPicFile(hPrintRec, NULL, NULL, NULL, &theStatus);
  259.  
  260.  
  261. /* that's all for now */
  262.         
  263.     if (hPrintRec) DisposeHandle((Handle) hPrintRec);
  264.         
  265. } /* Print */
  266.  
  267. /*------------------------------------------------------------------------*/
  268.  
  269. pascal TPPrDlg MyJobDlgInit (hPrint)
  270. THPrint hPrint;
  271. /*
  272.    this routine appends items to the standard job dialog and sets up the
  273.    user fields of the printing dialog record TPRDlg
  274.  
  275.    This routine will be called by PrDlgMain
  276. */
  277.  
  278. {
  279.     short      firstItem;    /* first new item number */
  280.     
  281.     short      itemType, item;
  282.     Handle     itemH;
  283.     Rect       itemBox;
  284.     
  285.     firstItem = Append_DITL(PrtJobDialog, MyDITL); /*call routine to do this */
  286.     
  287.     prFirstItem = firstItem; /* save this so MyJobItems can find it */
  288.  
  289. /* now we'll set up our DITL items -- The radio buttons */
  290.     
  291.     for (item = 5; item <= 7; item++)
  292.     {
  293.         GetDItem((DialogPtr) PrtJobDialog,firstItem + item -1,&itemType,&itemH,&itemBox);
  294.         SetCtlValue((ControlHandle) itemH, (item == 5));
  295.     }
  296.     
  297. /* now we'll set up the second of our DITL items  -- The checkbox */
  298.  
  299.     GetDItem((DialogPtr) PrtJobDialog,firstItem +2,&itemType,&itemH,&itemBox);
  300.     SetCtlValue((ControlHandle) itemH,1);
  301.  
  302. /*
  303.    Now comes the part where we patch in our item handler.  We have to save
  304.    the old item handler address, so we can call it if one of the standard
  305.    items is hit, and put our item handler's address in pItemProc field of
  306.    the TPrDlg struct
  307. */
  308.  
  309.     prPItemProc = (long)PrtJobDialog->pItemProc;
  310.     
  311. /* Now we'll tell the modal item handler where our routine is */
  312.     PrtJobDialog->pItemProc = (ProcPtr)&MyJobItems;
  313.     
  314.  
  315. /* PrDlgMain expects a pointer to the modified dialog to be returned...*/
  316.     return PrtJobDialog;
  317.     
  318. } /*myJobDlgInit*/
  319.  
  320. /*-----------------------------------------------------------------------*/
  321.  
  322. /* here's the analogue to the SF dialog hook */
  323.  
  324. pascal void MyJobItems(theDialog,itemNo)
  325. TPPrDlg     theDialog;
  326. short       itemNo;
  327.  
  328. { /* MyJobItems */
  329.     short   myItem;
  330.     short   firstItem, item, itemType, theValue;
  331.     Handle  itemH;
  332.     Rect    itemBox;
  333.     
  334.     firstItem = prFirstItem;      /* remember, we saved this in myJobDlgInit */
  335.     myItem = itemNo-firstItem+1;  /* "localize" current item No */
  336.     if (myItem > 0)               /* if localized item > 0, it's one of ours */
  337.     {
  338.         /* find out which of our items was hit */
  339.  
  340.         switch (myItem)
  341.         {
  342.             case 1:            /*    Static text.    */
  343.                 break;
  344.             case 2:            /*    Edit text.        */
  345.                 break;
  346.             case 3:            /*    Check box.        */
  347.                        GetDItem((DialogPtr) theDialog,firstItem +2,&itemType,&itemH,&itemBox);
  348.                      theValue = GetCtlValue((ControlHandle) itemH);
  349.                      SetCtlValue((ControlHandle) itemH, theValue != 1);
  350.                 break;
  351.             case 4:            /*    Push button.    */
  352.                 break;
  353.             case 5:            /*    Radio buttons    */
  354.             case 6:
  355.             case 7:
  356.                    for (item = 5; item <= 7; item++)
  357.                    {
  358.                        GetDItem((DialogPtr) theDialog,firstItem +item -1,&itemType,&itemH,&itemBox);
  359.                      SetCtlValue((ControlHandle) itemH, item == myItem);
  360.                    }
  361.                 break;
  362.             case 8:            /*    Edit text.        */
  363.                 break;
  364.             default: Debugger(); /* OH OH */    
  365.         } /* switch */
  366.     } /* if (myItem > 0) */
  367.     else /* chain to standard item handler, whose address is saved in 
  368.               prPItemProc */
  369.     {
  370.         ((pascal void (*) (TPPrDlg, short)) (Ptr) prPItemProc) (theDialog, itemNo);
  371.     }
  372. } /* MyJobItems */
  373.  
  374.  
  375. main()
  376. {    
  377.     Rect        myWRect;
  378.     
  379.     InitGraf(&thePort);
  380.     InitFonts();
  381.     InitWindows();
  382.     InitMenus();
  383.     InitDialogs(nil);
  384.     InitCursor();
  385.     SetRect(&myWRect,50,260,350,340);
  386.     
  387.     /* call the routine that does printing */
  388.     PrOpen();
  389.     err = Print();
  390.     
  391.     PrClose();
  392. } /* main */
  393.